package main.java.com.lee.juc;

import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.StampedLock;

/**
 * @Description TODO
 * @Author winston
 * @DateTime 2022/2/11
 */
public class StampedLockDemo {
    static Map<String, String> MAP = new HashMap<>();
    static StampedLock lock = new StampedLock();

    public static void main(String[] args) throws InterruptedException {
        Runnable writeTarget = () -> write("key", "value");
        Runnable readTarget = () -> optimisticRead("key");
        Thread writeThread = new Thread(writeTarget, "writeThread");
        Thread readThread = new Thread(readTarget, "readThread");
        readThread.start();
        Thread.sleep(1000);
        writeThread.start();
    }

    private static void write(String key, String value) {
        long stamp = lock.writeLock();
        try {
            System.out.println(Thread.currentThread().getName() + "抢占了写锁");
            Thread.sleep(1000);
            MAP.put(key, value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlockWrite(stamp);
        }
    }

    private static String pessimisticRead(String key) {
        long stamp = lock.readLock();
        try {
            System.out.println(Thread.currentThread().getName() + "抢占了读锁");
            Thread.sleep(1000);
            return MAP.get(key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlockRead(stamp);
        }
        return null;
    }

    private static String optimisticRead(String key) {
        long stamp = lock.tryOptimisticRead();
        String value;
        if (stamp != 0) {
            System.out.println("乐观锁读取成功");
            value = MAP.get(key);
        } else {// 说明当前为写锁模式
            return pessimisticRead(key);// 直接返回
        }
        // 验证乐观锁
        if (!lock.validate(stamp)) {//写锁被占用过
            pessimisticRead(key);//直接返回
        } else {
            return value;
        }
        return value;
    }
}
